#ifndef SESSION_MANAGER_P_H
#define SESSION_MANAGER_P_H

#include <QtCore/QRegExp>
#include <QtCore/QList>
#include <QtCore/QHash>
#include <QtCore/QQueue>
#include <QtCore/QThread>
#include <QtSql/QSqlDatabase>
#include "global.h"
#include "sessionmanager/source_server.h"
#include "dbmanager/sql_query.h"

namespace smsrouter {

class SessionManager;

class SessionManagerPrivate : public QObject {
  Q_OBJECT
public:
  SessionManagerPrivate(SessionManager *parent);

  ~SessionManagerPrivate();

  friend class SessionManager;

  SessionManager *parent;

  QHash<smpp::sessions::ServerAsyncSession *, quint32> sn_src_sessions;

  QHash<smpp::sessions::ServerAsyncSession *, quint32> src_sessions;

  QHash<smpp::sessions::ServerAsyncSession *, QList<SrcSubmitSm *> *>
    submit_src_session;

  QHash<smpp::sessions::ServerAsyncSession *, QList<SrcSubmitSm *> *>
    submit_resp_src_session;

  QHash<smpp::sessions::ServerAsyncSession *, QList<SrcDeliverSm *> *>
    deliver_src_session;

  SourceServer *src_server;

  QHash<smpp::sessions::ClientAsyncSession *, quint32> sn_dest_sessions;

  QHash<smpp::sessions::ClientAsyncSession *, quint32> dest_sessions;

  QHash<smpp::sessions::ClientAsyncSession *, QList<DestSubmitSm *> *>
    submit_dest_session;

  QHash<smpp::sessions::ClientAsyncSession *, QList<DestDeliverSm *> *>
    deliver_dest_session;

  QHash<SrcSubmitSm *, quint32> submit_src_error;

  QQueue<quint32> dest_rest_sessions;

  QThread *thread;

  State state;

  quint32 genSrcSequenceNumber(smpp::sessions::ServerAsyncSession *session);

  quint32 genDestSequenceNumber(smpp::sessions::ClientAsyncSession *session);

signals:

  void sigStop();

  void sigResponce(SrcSubmitSm *);

  void sigSend(DestSubmitSm *);

  void sigSend(SrcDeliverSm *);

private slots:

  void threadStarted();

  void stop();

  void newSrc(int socket_descriptor);

  void openedDest();

  void closedDest();

  void restartDest();

  void errorDest(smpp::sessions::ErrorCode code);

  void send(DestSubmitSm *);

  void send(SrcDeliverSm *);

  void receiveDest(const smpp::pdu::BindTransmitterResp &p);

  void receiveDest(const smpp::pdu::BindReceiverResp &p);

  void receiveDest(const smpp::pdu::BindTransceiverResp &p);

  void receiveDest(const smpp::pdu::UnbindResp &p);

  void receiveDest(const smpp::pdu::SubmitSmResp &p);

  void receiveDest(const smpp::pdu::DeliverSm &p);

  void receiveDest(const smpp::pdu::QuerySmResp &p);

  void receiveDest(const smpp::pdu::ReplaceSmResp &p);

  void receiveDest(const smpp::pdu::CancelSmResp &p);

  void receiveDest(const smpp::pdu::EnquireLink &p);

  void receiveDest(const smpp::pdu::EnquireLinkResp &p);

  void stateChangedDest(const smpp::sessions::SessionStates state);

  void sessionInitTimeoutDest();

  void enquireLinkTimeoutDest();

  void inactivityTimeoutDest();

  void outStatusDest(const smpp::pdu::Header &header,
                     smpp::sessions::StatusMessage status);

  void inStatusDest(const smpp::pdu::Header &header,
                    smpp::sessions::StatusMessage status);

  void openedSrc();

  void closedSrc();

  void responce(SrcSubmitSm *);

  void errorSrc(smpp::sessions::ErrorCode code);

  void receiveSrc(const smpp::pdu::BindTransmitter &p);

  void receiveSrc(const smpp::pdu::BindReceiver &p);

  void receiveSrc(const smpp::pdu::BindTransceiver &p);

  void receiveSrc(const smpp::pdu::Unbind &p);

  void receiveSrc(const smpp::pdu::SubmitSm &p);

  void receiveSrc(const smpp::pdu::DeliverSmResp &p);

  void receiveSrc(const smpp::pdu::QuerySm &p);

  void receiveSrc(const smpp::pdu::ReplaceSm &p);

  void receiveSrc(const smpp::pdu::CancelSm &p);

  void receiveSrc(const smpp::pdu::EnquireLink &p);

  void receiveSrc(const smpp::pdu::EnquireLinkResp &p);

  void stateChangedSrc(smpp::sessions::SessionStates state);

  void sessionInitTimeoutSrc();

  void enquireLinkTimeoutSrc();

  void inactivityTimeoutSrc();

  void outStatusSrc(const smpp::pdu::Header &header,
                    smpp::sessions::StatusMessage status);

  void inStatusSrc(const smpp::pdu::Header &header,
                   smpp::sessions::StatusMessage status);

private:

  void initMain();

  void createSrc(int sock_desc,
                 int in_speed, // msec
                 int out_speed, // msec
                 int session_init_time,
                 int enquire_link_time,
                 int inactivity_time,
                 int transaction_time,
                 int max_in_trans,
                 int max_out_trans);

  void createDest(quint32 dest_session_id,
                  const QHostAddress &addr,
                  quint16 port,
                  int in_speed, // msec
                  int out_speed, // msec
                  int session_init_time,
                  int enquire_link_time,
                  int inactivity_time,
                  int transaction_time,
                  int max_in_trans,
                  int max_out_trans);

  void destroySrc(smpp::sessions::ServerAsyncSession *session);

  void destroyDest(smpp::sessions::ClientAsyncSession *session);

  void inStatusSrcSubmitSm(const smpp::pdu::Header &header,
                           smpp::sessions::ServerAsyncSession *session,
                           quint32 error_code);

  void outStatusSrcDeliverSm(const smpp::pdu::Header &header,
                             smpp::sessions::ServerAsyncSession *session,
                             quint32 error_code);

  void outStatusDestSubmitSm(const smpp::pdu::Header &header,
                             smpp::sessions::ClientAsyncSession *session,
                             quint32 error_code);

  void inStatusDestDeliverSm(const smpp::pdu::Header &header,
                             smpp::sessions::ClientAsyncSession *session,
                             quint32 error_code);

  QString stateToString(smpp::sessions::SessionStates state) const;

  void checkState();

  void setState(State state);
};

} // namespace smsrouter

#endif // SESSION_MANAGER_P_H
